package model;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.Vector;


import toolkit.Counter;
import toolkit.Order;
import toolkit.Random;

public class CardContainer {
	
	protected Vector<Card> cards = new Vector<Card>();

	static private Order order;
	
	public void addCard(Card card)
	{
		if (card != null)
		{
			cards.addElement(card);
		}
	}
	
	public void addCards(Collection<Card> cards)
	{
		for (Card card: cards)
		{
			addCard(card);
		}
	}
	
	public Card getCard(int index)
	{
		if (index >= 0 && index < cards.size())
		{
			return cards.get(index);
		}
		
		return null;
	}
	
	public ArrayList<Card> getCards()
	{
		return new ArrayList<Card>(cards);
	}
	
	public void shuffle()
	{
		Collections.shuffle(cards, new Random());
	}
	
	public HashMap<CardSuit, ArrayList<Card>> getCardsBySuit()
	{
		HashMap<CardSuit, ArrayList<Card>> cardsBySuit = new HashMap<CardSuit, ArrayList<Card>>();
		
		for (CardSuit suit: CardSuit.values())
		{
			cardsBySuit.put(suit, new ArrayList<Card>());
		}
		
		for (Card card: cards)
		{
			cardsBySuit.get(card.getSuit()).add(card);
		}
		
		return cardsBySuit;
	}
	
	public EnumMap<CardSuit, EnumMap<CardRank, Counter>> countCardsGrouped()
	{
		EnumMap<CardSuit, EnumMap<CardRank, Counter>> map = new EnumMap<CardSuit, EnumMap<CardRank, Counter>>(CardSuit.class);
		
		for (CardSuit suit: CardSuit.values())
	    {
	    	EnumMap<CardRank, Counter> suitMap = new EnumMap<CardRank, Counter>(CardRank.class);
	    	
	        for (CardRank rank: CardRank.values())
	        {
	        	suitMap.put(rank, new Counter());
	        }
	        
	        map.put(suit, suitMap);
	    }
		
		for (Card card: cards)
		{
			map.get(card.getSuit()).get(card.getRank()).increment();
		}
		
		return map;
	}
	
	public void removeCard(Card card)
	{
		cards.removeElement(card);
	}
	
	public void removeCard(int index)
	{
		if (index >= 0 && index < cards.size())
		{
			cards.removeElementAt(index);
		}
	}
	
	public int size()
	{
		return cards.size();
	}
	
	public void clear()
	{
		cards.removeAllElements();
	}
	
	public void setOrder(Order order)
	{
		CardContainer.order = order;
	}
	
	private final static Comparator<Card> sortBySuit = new Comparator<Card>()
	{
		public int compare(Card c1, Card c2)
		{
			// 1 = down, -1 = up
			if
			(
				(
					(order == Order.ASC && c1.getSuit().toInteger() < c2.getSuit().toInteger())
					||
					(order == Order.DESC && c1.getSuit().toInteger() > c2.getSuit().toInteger())
				)
				||
				c1.getSuit() == c2.getSuit()
			)
			{
				return -1;
			}
			
			return 1;
		}
	};
	
	public void sortBySuit()
	{
		sortBySuit(Order.ASC);
	}
	
	public void sortBySuit(Order order)
	{
		setOrder(Order.ASC);
		
		Collections.sort(cards, sortByRank);
		
		setOrder(order);
		
		Collections.sort(cards, sortBySuit);
		
		/*Vector<Card> cardsSorted = new Vector<Card>();
		
		while (cards.size() > 0)
		{
			int index = 0;
			
			Card next = cards.get(0);
			
			for (int i = 1; i < cards.size(); i++)
			{
				Card card = cards.get(i);
				
				if
				(
					// Got the card a lower suit integer value? Make this the next card.
					card.getSuit().toInteger() < next.getSuit().toInteger()
					||
					(
						// If not, does it belong to the same suit?
						card.getSuit() == next.getSuit()
						&&
						// And does has it a better next rank integer value? Make this the next card.
						(
							// Lowest get first.
							(order == Order.ASC && card.getRank().toInteger() < next.getRank().toInteger())
							||
							// Highest get first.
							(order == Order.DESC && card.getRank().toInteger() > next.getRank().toInteger())
						)
					)
				)
				{
					index = i;
					
					next = card;
				}
			}
			
			cards.removeElementAt(index);
			
			cardsSorted.addElement(next);
		}
		
		cards = cardsSorted;*/
	}

	private final static Comparator<Card> sortByRank = new Comparator<Card>()
	{
		public int compare(Card c1, Card c2)
		{
			// 1 = down, -1 = up
			if
			(
				(
					(order == Order.ASC && c1.getRank().toInteger() < c2.getRank().toInteger())
					||
					(order == Order.DESC && c1.getRank().toInteger() > c2.getRank().toInteger())
				)
				||
				c1.getRank() == c2.getRank()
			)
			{
				return -1;
			}
			
			return 1;
		}
	};
	
	public void sortByRank()
	{
		sortByRank(Order.ASC);
	}
	
	public void sortByRank(Order order)
	{
		setOrder(Order.ASC);
		
		Collections.sort(cards, sortBySuit);
		
		setOrder(order);
		
		Collections.sort(cards, sortByRank);
		
		/*Vector<Card> cardsSorted = new Vector<Card>();
		
		while (cards.size() > 0)
		{
			int index = 0;
			
			Card next = cards.get(0);
			
			for (int i = 1; i < cards.size(); i++)
			{
				Card card = cards.get(i);
				
				if
				(
					// Got the card a better next rank integer value? Make this the next card.
					(
						// Lowest get first.
						(order == Order.ASC && card.getRank().toInteger() < next.getRank().toInteger())
						||
						// Highest get first.
						(order == Order.DESC && card.getRank().toInteger() > next.getRank().toInteger())
					)
					||
					(
						// If not, does it belong to the same rank?
						// And does has it a lower suit integer value? Make this the next card.
						card.getRank() == next.getRank() && card.getSuit().toInteger() < next.getSuit().toInteger()
					)
				)
				{
					index = i;
					
					next = card;
				}
			}
			
			cards.removeElementAt(index);
			
			cardsSorted.addElement(next);
		}
		
		cards = cardsSorted;*/
	}
	
	public String toString()
	{
		String container = "";
		
		for (Card card: cards)
		{
			container += card + "\n";
		}
		
		return container;
	}
}
